<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>线程机制与事件机制</title>
</head>

<body>
    <script>
        /**
         * 线程机制与事件机制
         *  1. 进程

                程序的一次执行，它占有一片独有的内存空间
                可以通过windows任务管理器查看进程
            2. 线程

                是进程内的一个独立执行单元
                是程序执行的一个完整流程
                是CPU的最小的调度单元
            3. 相关知识

                应用程序必须运行在某个进程的某个线程上
                一个进程中至少有一个运行的线程：主线程，进程启动后自动创建
                一个进程中也可以同时运行多个线程，我们会说程序是多线程运行的
                一个进程内的数据可以供其中的多个线程直接共享
                多个进程之间的数据是不能直接共享的
                线程池（Thread Pool）：保存多个线程对象的容器，实现线程对象的反复利用
            4. 浏览器是单进程还是多进程

                1.单进程：
                    firefox
                    老版IE
                2.多进程：
                    Chrome
                    新版IE
            5. javascript从诞生之日起就是一门单线程的非阻塞的脚本语言。这是由其最初的用途来决定的：与浏览器交互。

                单线程意味着，javascript代码在执行的任何时候，都只有一个主线程来处理所有的任务。

                非阻塞:

                而非阻塞则是当代码需要进行一项异步任务（无法立刻返回结果，需要花一定时间才能返回的任务，如I/O事件）的时候，主线程会挂起（pending）这个任务，然后在异步任务返回结果的时候再根据一定规则去执行相应的回调。
            
        */

        /***
         * 浏览器内核
         * 内核模块

            JS引擎模块：负责js程序的编译与运行

            html，css文档解析模块：腐恶页面文本的解析

            DOM/CSS模块：负责DOM/CSS在内存中的相关处理

            布局和渲染模块：负责页面的布局和效果的绘制（内存中的对象）

              （运行在主线程上）

            …………………………………………………………………………………………………………

              （运行在分线程上）

            定时器模块：负责定时器的管理

            事件响应模块：负责事件的管理

            网络请求模块：负责ajax请求
        */

        /**
         * 定时器引发的思考
            定时器真是定时执行的吗？

            定时器并不能保证真正定时执行
            一般会延迟一丁点（可以接受），也有可能延迟很长时间（不能接受）
            定时器回调函数是在分线程执行的吗？

            在主线程执行的，js是单线程的

            定时器是如何实现的？
        */

        /**
         * JS是单线程执行的
            1. 如何证明js执行时单线程的？

                setTimeout（）的回调函数是在主线程执行的
                定时器回调函数只有在运行栈中的代码全部执行完之后才有可能执行
            2. 为什么js要用单线程模式，而不是多线程模式？

                Javascript的单线程，与它的用途有关作为，浏览器脚本语言，Javascript的主要用途是与用户交互，以及操作DOM，这决定了它只能是单线程，否则会带来很复杂的同步问题。
            3.代码的分类

                初始化代码
                回调代码
            4.js引擎执行代码的基本流程

                先执行初始化代码：包含一些特别的代码，比如设置定时器、绑定事件监听、发送ajax请求
                后面在某些时刻才会执行回调代码
        */
        /**
         * 浏览器的时间循环（轮询）模型
         *   1. 模型的2个重要组成部分：
 
                 事件（定时器/DOM事件/Ajax）管理模块
                 回调队列
             2. 模型的运转流程：
 
                 执行初始化代码，将事件回调函数交给对应模块管理
                 当事件发生时，管理模块会将回调函数及其数据添加到回调队列中
                 只有当初始化代码执行完后（可能要一定时间），才会遍历去回调队列中的回调函数执行。
        */

        /**
         * 事件队列（Task Queue）
         *   JS引擎遇到一个异步事件后并不会一直等待其返回结果，而是会将这个事件挂起，
         *   继续执行执行栈中的其他任务,当一个异步事件返回结果后，
         *   js会将这个事件加入与当前执行栈不同的另一个队列，我们称之为事件队列。
             被放入事件队列不会立刻执行其回调，而是等待当前执行栈中的所有任务都执行完毕，
             主线程处于闲置状态时，主线程会去查找事件队列是否有任务。如果有，那么主线程会从中取出排在第一位的事件，
             并把这个事件对应的回调放入执行栈中，然后执行其中的同步代码…，如此反复，这样就形成了一个无限的循环。
             这就是这个过程被称为“事件循环（Event Loop）”的原因。
             (浏览器事件循环模型原理图2)中的stack表示我们所说的执行栈，web apis则是代表一些异步事件，而callback queue即事件队列。
 
             以上的事件循环过程是一个宏观的表述，实际上因为异步任务之间并不相同，因此他们的执行优先级也有区别。不同的异步任务被分为两类：微任务（micro task）和宏任务（macro task）。
 
        */
        /**
         * JS中用来存储待执行回调函数的队列包含2个不同特定的列队
         *    1.MacroTask（宏任务）
         *        script全部代码、setTimeout、setInterval、setImmediate（浏览器暂时不支持，只有IE10支持，具体可见MDN）、I/O、UI Rendering。
         *    2.MicroTask（微任务）
         *        Process.nextTick（Node独有）、Promise.then catch finally、Object.observe(废弃)、MutationObserver、Async/Await(实际就是promise)
        */
        /**
         * JS执行时会区别这2个队列:

            JS执行引擎首先必须执行所有的初始化同步任务代码
            每次准备取出第一个宏任务执行前,都要将所有的微任务一个一个取出来执行

            在一个事件循环中，异步事件返回结果后会被放到一个任务队列中。然而，根据这个异步事件的类型，
            这个事件实际上会被对应的宏任务队列或者微任务队列中去。并且在当前执行栈为空的时候，
            主线程会 查看微任务队列是否有事件存在。如果不存在，那么再去宏任务队列中取出一个事件并把对应的回到加入当前执行栈；
            如果存在，则会依次执行队列中事件对应的回调，直到微任务队列为空，
            然后去宏任务队列中取出最前面的一个事件，把对应的回调加入当前执行栈…如此反复，进入循环。
        */
        setTimeout(() => {
            console.log('timeout callback1（）')//立即放入宏队列
            Promise.resolve(3).then(
                value => {
                    console.log('Promise onResolved3()', value)//当这个宏任务执行后 立马放入微队列,所以这个微任务执行完后下个宏任务才能执行 
                }
            )
        }, 0)

        setTimeout(() => {
            console.log('timeout callback2（）') //立即放入宏队列,
        }, 0)

        Promise.resolve(1).then(
            value => {
                console.log('Promise onResolved1()', value)//立即放入微队列
                setTimeout(() => {
                    console.log('timeout callback3（）', value) //立即放入宏任务
                }, 0)
            }
        )

        Promise.resolve(2).then(
            value => {
                console.log('Promise onResolved2()', value)//立即放入微队列
            }
        )
        console.log('同步代码') //同步代码立即执行 
        /**
         * '同步代码',
            'Promise onResolved1()',
            'Promise onResolved2()',
            'timeout callback1（）',
            'Promise onResolved3()',
            'timeout callback2（）',
            'timeout callback3（）'
        */

    </script>
</body>

</html>